package com.gitee.feizns.utils.ftp;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * ftp
 */
public class FTPUtils implements FtpService {

    private static final Logger logger = LoggerFactory.getLogger(FTPUtils.class);

    /**
     * 默认的超时时间
     */
    public static final int DEFAULT_TIMEOUT = 120000;

    /**
     * 默认编码
     */
    public static final String DEFAULT_CHARSET = "UTF-8";

    /**
     * 默认的缓存大小
     */
    public static final int DEFAULT_BUF_SIZE = 10240;

    private FTPClient ftpClient;

    private String basePath;

    private String serverIP;

    private int port;

    private String userName;

    private String password;

    private int bufferSize;

    private int timeout;

    public FTPUtils(String serverIP, int port, String userName, String password, String basePath, int bufferSize, int timeout) throws IOException {
        ftpClient = new FTPClient();
        this.serverIP = serverIP;
        this.port = port;
        this.userName = userName;
        this.password = password;
        this.basePath = basePath;
        this.bufferSize = bufferSize;
        this.timeout = timeout;
    }

    public FTPUtils(String serverIP, int port, String userName, String password, String basePath) throws IOException {
        this(serverIP, port, userName, password, basePath, DEFAULT_BUF_SIZE, DEFAULT_TIMEOUT);
    }

    //see https://www.cnblogs.com/huhaoshida/p/5412615.html
    private void connect() throws IOException {
        if ( ftpClient.isConnected() == false ) {
            ftpClient.connect(serverIP, port);
            ftpClient.enterLocalPassiveMode();  //服务器被动模式，需开启端口
            ftpClient.login(userName, password);
            ftpClient.setBufferSize(bufferSize);
            ftpClient.setControlEncoding(DEFAULT_CHARSET);
            ftpClient.setDataTimeout(timeout);
            ftpClient.setConnectTimeout(timeout);
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        }
    }

    private void close() {
        if ( ftpClient.isConnected() ) {
            try {
                try {
                    ftpClient.logout();
                } finally {
                    ftpClient.disconnect();
                }
            } catch (IOException e) {
                logger.warn("关闭ftp连接异常", e);
            }
        }
    }

    /**
     * 上传文件制定目录
     *
     * @param dir
     * @param fileName
     * @param localFile
     * @return
     * @throws IOException
     */
    public boolean uploadFile(String dir, String fileName, String localFile) {
        try ( InputStream is = new FileInputStream(localFile) ) {
            return uploadFile(dir, fileName, is);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 上传文件到指定目录
     *
     * @param dir
     * @param fileName
     * @param is
     * @return
     */
    public boolean uploadFile(String dir, String fileName, InputStream is) {
        try {
            connect();
            if (dir != null)
                changeDirectory( concat(basePath, dir) );
            return ftpClient.storeFile(fileName, is);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            close();
        }
    }

    private static String concat(String... path) {
        return Arrays.stream(path).filter(Objects::nonNull).collect(Collectors.joining());
    }

    /**
     * 切换目录
     *
     * @param path 创建目录
     * @return 创建标志
     * @throws IOException 异常
     */
    public boolean changeDirectory(String path) throws IOException {
        return ftpClient.changeWorkingDirectory(path);
    }

    /**
     * 创建目录
     *
     * @param path 创建目录
     * @return 创建标志
     * @throws IOException 异常
     */
    public boolean createDirectory(String path) throws IOException {
        return ftpClient.makeDirectory(path);
    }

}
